using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using UnityEngine;


public class MyUdpSlice
{
    public byte[] m_Data = new byte[SocketHelper.UDP_Slice_Head_Len + SocketHelper.UDP_Slice_Max_Body_Size];
    public int m_BodyLen;
    public bool m_IsReady;
    public long m_LastTime;
    public int m_RetryCount;
}


public class MyUdpPacket
{
    public MyUdpSlice[] m_Slices;

    public ushort GetMsgId()
    {
        return BitConverter.ToUInt16(m_Slices[0].m_Data, 0);
    }

    public bool CheckAllReady(out string str)
    {
        str = "";

        int totalLen = 0;
        for (int i = 0; i < m_Slices.Length; ++i)
        {
            var slice = m_Slices[i];
            if (null == slice || !slice.m_IsReady)
                return false;

            totalLen += slice.m_BodyLen;
        }

        byte[] bytes = new byte[totalLen]; //todo: 复用
        int offset = 0;
        for (int i = 0; i < m_Slices.Length; ++i)
        {
            var slice = m_Slices[i];
            Buffer.BlockCopy(slice.m_Data, SocketHelper.UDP_Slice_Head_Len, bytes, offset, slice.m_BodyLen);
            offset += slice.m_BodyLen;
        }
        str = Encoding.UTF8.GetString(bytes);

        return true;
    }

}



public static class SocketHelper
{
    public const int Packet_Head_Len = 4;
    public const int UDP_Slice_Head_Len = 8;
    public const int UDP_Slice_Max_Body_Size = 512;

    public struct ThreadMessage
    {
        public string m_Cmd;
        public string m_Content;
        public object m_Obj;
        //public object m_Obj2;
    }


    public struct BeginReceiveState
    {
        public Socket m_Socket;
        public byte[] m_Buff;
        public int m_PacketRecvLen;
        public byte[] m_Temp4Bytes;

        public int BuffRemainLen
        {
            get { return m_Buff.Length - m_PacketRecvLen; }
        }
    }


    public struct BeginSendState
    {
        public Socket m_Socket;
        public byte[] m_Bytes; //要发送的数据
        public int m_SendLen; //已发送字节数
    }


    public static string GetIpV4Address()
    {
        // 获取本地主机的相关信息
        var hostName = Dns.GetHostName();
        Debug.Log($"hostName:{hostName}");
        IPHostEntry host = Dns.GetHostEntry(hostName);

        // 遍历所有IP地址
        string result = "";
        foreach (var ipAddress in host.AddressList)
        {
            if (IPAddress.IsLoopback(ipAddress)) continue; //非本地链接地址
            if (ipAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6) continue; //IPv6地址

            Debug.Log($"{ipAddress.ToString()}: ipv6LinkLocal:{ipAddress.IsIPv6LinkLocal}, ipv6Multi:{ipAddress.IsIPv6Multicast}, ipv6SiteLocal:{ipAddress.IsIPv6SiteLocal}, ipv6Teredo:{ipAddress.IsIPv6Teredo}");
            if (ipAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
            {
                result = ipAddress.ToString();
            }
        }

        return result;
    }


    public static bool IsPacketReady(byte[] buff, int readedLen, int notReadLen, out int bodyLen)
    {
        bodyLen = 0;
        if (notReadLen < Packet_Head_Len)
            return false;

        bodyLen = BitConverter.ToInt32(buff, readedLen);
        if (notReadLen < Packet_Head_Len + bodyLen)
            return false;
        
        return true;
    }

    public static bool IsUdpSliceReady(byte[] buff, int readedLen, int notReadLen, out int opCode, out int bodyLen)
    {
        opCode = 0;
        bodyLen = 0;

        if (notReadLen < UDP_Slice_Head_Len)
            return false;

        //msgId: 2-byte, [-32768, 32767]或[0, 65535]
        //opCode: 1-byte, [-128, 127]或[0, 255]
        //bodyLen: 1-byte
        //sliceIndex: 2-byte
        //sliceCount: 2-byte

        opCode = buff[readedLen + 2];
        bodyLen = buff[readedLen + 3];
        if (notReadLen < UDP_Slice_Head_Len + bodyLen)
            return false;

        return true;
    }

    public static void ConvertInt32To4Bytes(int v, byte[] bytes, int offset)
    {
        //int转byte[]
        if (BitConverter.IsLittleEndian) //[0]放最低的1-byte
        {
            bytes[offset] = (byte)(v & 0xFF);
            bytes[offset + 1] = (byte)((v >> 8) & 0xFF); //右移时, 最左侧补符号位
            bytes[offset + 2] = (byte)((v >> 16) & 0xFF);
            bytes[offset + 3] = (byte)((v >> 24) & 0xFF);
        }
        else
        {
            bytes[offset] = (byte)((v >> 24) & 0xFF); //从高bits开始写
            bytes[offset + 1] = (byte)((v >> 16) & 0xFF);
            bytes[offset + 2] = (byte)((v >> 8) & 0xFF);
            bytes[offset + 3] = (byte)(v & 0xFF);
        }
    }

    public static void ConvertInt16To2Bytes(short v, byte[] bytes, int offset)
    {
        if (BitConverter.IsLittleEndian) //[0]放最低的1-byte
        {
            bytes[offset] = (byte)(v & 0xFF);
            bytes[offset + 1] = (byte)((v >> 8) & 0xFF); //右移时, 最左侧补符号位
        }
        else
        {
            bytes[offset] = (byte)((v >> 8) & 0xFF); //从高bits开始写
            bytes[offset + 1] = (byte)(v & 0xFF);
        }
    }

    public static void Close(Socket so)
    {
        try
        {
            if (null != so)
                so.Close(); //同Stream那样, Close后不能再使用
        }
        catch (Exception ex)
        {
            Debug.LogWarning($"{ex.GetType().Name}:{ex.Message}");
        }
    }

    public static void ShutdownAndClose(Socket so)
    {
        try
        {
            if (null != so)
            {
                so.Shutdown(SocketShutdown.Both); //Shutdown无法唤醒线程中阻塞的Receive, Close才行
                so.Close();
            }
        }
        catch (Exception ex)
        {
            Debug.LogWarning($"{ex.GetType().Name}:{ex.Message}");
        }
    }

    public static long CurrentTimeMillis()
    {
        long ticks = DateTime.Now.Ticks - 2020l * 365 * 24 * 60 * 60 * 1000 * 10000;
        return ticks / 10000;
    }

    public static void RemoveNullElements<T>(List<T> list) where T : class
    {
        int ct = list.Count;
        if (ct <= 0) return;

        int j = 0;
        for (int i = 0; i < ct; ++i)
        {
            if (null == list[i])
            {
                j = i;
                i++;
                //非null元素前移
                for (; i < ct; ++i)
                {
                    if (null != list[i])
                        list[j++] = list[i];
                }
                break;
            }
        }
        
        list.RemoveRange(j, ct - j);
    }

}
